package org.sraosha.creator.handler;

import org.sraosha.creator.constants.FileConstants;
import org.sraosha.creator.constants.TemplateConstants;
import org.sraosha.creator.util.JdbcUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import lombok.extern.slf4j.Slf4j;
import org.sraosha.creator.pojo.ColumnOrAttribute;
import org.sraosha.creator.pojo.Model;

/**
 * 创建三层结构代码的处理器类
 *
 */
@Slf4j
public class GenerateBackEndCodeHandler extends AbstractHandler {

    public void handle() {
        super.handle();
    }

    /**
     * 收集数据，填充到model中
     *
     * @param tableName
     */
    @Override
    public void collect(String tableName) {
        log.info("开始执行GenerateThreeLayerCodeHandler类的collect方法");

        try {
            // 初始化成员变量
            this.init();

            // 获取表的注释
            String tableComment = databaseManager.findCommentByTableName(tableName);
            // 初始化model
            model = new Model();
            model.setPackageName(TemplateConstants.MODEL_PACKAGE_NAME);
            this.model.setTableComment(tableComment);
            this.model.setTableName(tableName);
            this.model.setClassName(JdbcUtil.tableNameToModelClassName(this.model.getTableName()));
            log.info("表" + tableName + "的注释：" + tableComment);

            // 获取列的名称、类型、注释
            ResultSet columnResultSet = databaseManager.findTableColumnByTableName(tableName);
            while (columnResultSet.next()) {
                // model文件
                String columnName = databaseManager.getColumnName(columnResultSet);
                String columnType = databaseManager.getColumnType(columnResultSet);
                String identityColumn = databaseManager.getIdentityColumn(columnResultSet);
                String columnComment = databaseManager.findCommentByTableNameAndColumnName(tableName, columnName);
                String attributeName = JdbcUtil.tableColumnNameToClassAttributeName(columnName);
                String attributeType = JdbcUtil.tableColumnTypeToClassAttributeType(columnType);
                this.model.getColumnOrAttributeList().add(new ColumnOrAttribute(columnName, columnType, columnComment, identityColumn, attributeName, attributeType));

                log.info("表" + tableName + "的列" + columnName + "的类型：" + columnType + "，注释：" + columnComment +
                        "，是否是主键：" + identityColumn + "，属性名：" + attributeName + "，属性类型：" + attributeType);
            }
            this.model.setInstanceName(JdbcUtil.tableNameToModelInstanceName(this.model.getTableName()));

            // mapper文件
            this.mapper.setClassName(JdbcUtil.tableNameToMapperClassName(this.model.getTableName()));
            this.mapper.setClassComment(this.model.getClassName() + TemplateConstants.MAPPER_CLASS_COMMENT_SUFFIX);

            // mapperXml文件
            this.mapperXml.setClassName(JdbcUtil.tableNameToMapperClassName(this.model.getTableName()));

            // service文件
            this.service.setClassName(JdbcUtil.tableNameToServiceInterfaceName(this.model.getTableName()));
            this.service.setInterfaceComment(this.model.getClassName() + TemplateConstants.SERVICE_INTERFACE_COMMENT_SUFFIX);
            this.service.setVariableName(JdbcUtil.tableNameToServiceVariableName(this.model.getTableName()));
            this.service.setClassComment(this.model.getClassName() + TemplateConstants.SERVICE_INTERFACE_COMMENT_SUFFIX);

            // serviceImpl文件
            this.serviceImpl.setClassName(JdbcUtil.tableNameToServiceImplName(this.model.getTableName()));
            this.serviceImpl.setClassComment(this.model.getClassName() + TemplateConstants.SERVICE_IMPL_CLASS_COMMENT_SUFFIX);

            // controller文件
            this.controller.setClassName(JdbcUtil.tableNameToControllerName(this.model.getTableName()));
            this.controller.setClassComment(this.model.getClassName() + TemplateConstants.CONTROLLER_CLASS_COMMENT_SUFFIX);

            // dto文件
            this.dataTransferObject.setClassName(JdbcUtil.tableNameToViewObjectName(this.model.getTableName()));
            this.dataTransferObject.setClassComment(this.model.getClassName() + TemplateConstants.VIEW_OBJECT_CLASS_COMMENT_SUFFIX);
            this.dataTransferObject.setInstanceName(JdbcUtil.tableNameToViewObjectInstanceName(this.model.getTableName()));

        } catch (SQLException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建文件
     */
    @Override
    public void createModel() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createModel方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.MODEL_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MODEL, this.model);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.model.getClassName() + FileConstants.JAVA_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建mapper文件
     */
    @Override
    public void createMapper() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createMapper方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.MAPPER_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MODEL, this.model);
            map.put(TemplateConstants.MAPPER, this.mapper);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.mapper.getClassName() + FileConstants.JAVA_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建xml文件
     */
    @Override
    public void createXML() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createXML方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.MAPPER_XML_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MAPPER_XML, this.mapperXml);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.mapperXml.getClassName() + FileConstants.XML_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建service文件
     */
    @Override
    public void createService() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createService方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.SERVICE_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MODEL, this.model);
            map.put(TemplateConstants.SERVICE, this.service);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.service.getClassName() + FileConstants.JAVA_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建serviceImpl文件
     */
    @Override
    public void createServiceImpl() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createServiceImpl方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.SERVICE_IMPL_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MODEL, this.model);
            map.put(TemplateConstants.MAPPER, this.mapper);
            map.put(TemplateConstants.SERVICE, this.service);
            map.put(TemplateConstants.SERVICE_IMPL, this.serviceImpl);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.serviceImpl.getClassName() + FileConstants.JAVA_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建controller文件
     */
    @Override
    public void createController() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createController方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.CONTROLLER_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MODEL, this.model);
            map.put(TemplateConstants.SERVICE, this.service);
            map.put(TemplateConstants.CONTROLLER, this.controller);
            map.put(TemplateConstants.VIEW_OBJECT, this.dataTransferObject);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.controller.getClassName() + FileConstants.JAVA_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 根据模板，创建dto文件
     */
    @Override
    public void createViewObject() {
        try {
            log.info("开始执行GenerateThreeLayerCodeHandler类的createViewObject方法");

            // 1、创建freemarker的配置对象
            Configuration configuration = new Configuration(Configuration.getVersion());
            // 2、设置模板文件所在目录
            configuration.setDirectoryForTemplateLoading(new File(FileConstants.TEMPLATE_FILE_PATH));
            // 3、设置字符集
            configuration.setDefaultEncoding("utf-8");
            // 4、加载模板文件
            Template template = configuration.getTemplate(TemplateConstants.VIEW_OBJECT_FILENAME);
            // 5、准备模板文件中所需要的数据，通常是通过map进行构造
            Map map = new HashMap();
            map.put(TemplateConstants.MODEL, this.model);
            map.put(TemplateConstants.VIEW_OBJECT, this.dataTransferObject);
            // 6、准备输出流对象，用于输出静态文件
            Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(FileConstants.OUTPUT_PATH + FileConstants.SEPARATOR + this.dataTransferObject.getClassName() + FileConstants.JAVA_FILE_SUFFIX), "UTF-8"));
            // 7、使用模板输出静态文件
            template.process(map, writer);
            // 8、关闭输出流
            writer.close();
        } catch (IOException ex) {
            ex.printStackTrace();
        } catch (TemplateException ex) {
            ex.printStackTrace();
        }
    }
}
